package pl.edu.pw.polygen.modeler.client.workspace;

import java.util.List;

import org.vaadin.contrib.component.svg.processing.Processing.MouseReleaseListener;
import org.vaadin.contrib.processing.svg.gwt.client.ui.VProcessingSVG;

import pl.edu.pw.polygen.modeler.client.graph.GraphHandler;
import pl.edu.pw.polygen.modeler.client.object.IPolygenObject;
import pl.edu.pw.polygen.modeler.client.utils.Scale;
import pl.edu.pw.polygen.modeler.client.workspace.listener.IWorkspaceListener;
import pl.edu.pw.polygen.modeler.client.workspace.listener.SelectListener;

import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.UIDL;

/**
 * Simple VProcessingSVG test application.
 * 
 */
public class Workspace extends VProcessingSVG implements IWorkspace {

	private boolean mouseDownCatch = false;	
	private IWorkspaceListener workspaceListener;	
	private PolygenContainer polygenContainer;
	private Editor editor;
	private boolean holded = false;
	private boolean selected = false;
	private int mouseClickedX;
	private int mouseClickedY;
	private Scale scale;
	private static int counter = 0;
	private boolean isInitalized = false;
	private int id;
	private boolean boundariesVisibility=false;
	private boolean moveable = false;
	
	public Workspace() {
		super();
		id = counter;
		GraphHandler.getInstance(id).clear();
		counter++;
		scale = Scale.getInstance();
		polygenContainer = new PolygenContainer();
		workspaceListener = new SelectListener(this);
	}

	/** This method will be called only once during initializing. */
	@Override
	public void setup() {
		init();
		this.getCanvas().setWidth("500px");
		this.getCanvas().setHeight("500px");

		// By setting doClear false, canvas wont be cleared for every frame.
		// Default value is true.
		doClear = false;

		// Set canvas size
		//size(1000, 500);

		// Set stroke weight in pixels
		strokeWeight(10);

		// Set frame rate
		frameRate(30);

		// Initial coordinates

		// Fill canvas grey
		background(100);

		// Set fill-color to blue
		fill(0, 121, 184);

		// Set stroke-color white
		stroke(255);
	}
	
	public void init(){
		MouseAction mouseAction = new MouseAction();
		this.getCanvas().addMouseDownHandler(mouseAction);
		this.getCanvas().addMouseUpHandler(mouseAction);
		this.getCanvas().addMouseMoveHandler(mouseAction);
		this.getCanvas().addMouseWheelHandler(mouseAction);
	}
	
	
	
	@Override
	public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
		
		if(isInitalized==false){
			super.updateFromUIDL(uidl, client);
			isInitalized=true;
			if(uidl.hasVariable("editorWidth") && uidl.hasVariable("editorHeight")){
				int width = uidl.getIntVariable("editorWidth");
				int height = uidl.getIntVariable("editorHeight");
				getCanvas().setPixelSize(width, height);
			}
		}
	}

	public String getTag(){
		return "worskpace";
	}

	public Editor getEditor() {
		return editor;
	}

	public void setEditor(Editor editor) {
		this.editor = editor;
	}

	/** This method will be called on every frame. */
	@Override
	public void draw() {
		for(IPolygenObject o :polygenContainer.getPolygenObjects()){
			o.draw();
		}
		if(moveable == true){
			int dx = mouseX - mouseClickedX;
			int dy = mouseY - mouseClickedY;
			mouseClickedX = mouseX;
			mouseClickedY = mouseY;
			shiftSelectedObjects(dx, dy);
		}
	}
	
	public void removeFromSelected(IPolygenObject o){
		polygenContainer.removeFromSelected(o);
	}
	
	public void addToSelected(IPolygenObject o){
		polygenContainer.addToSelected(o);
	}
	
	public void removeFromHolded(IPolygenObject o){
		polygenContainer.removeFromHolded(o);
	}
	
	public void addToHolded(IPolygenObject o){
		polygenContainer.addToHolded(o);
	}
	
	@Override
	public void add(IPolygenObject o) {
		polygenContainer.add(o);
	}
	
	@Override
	public boolean contains(IPolygenObject o) {
		return polygenContainer.contains(o);
		
	}

	@Override
	public void remove(IPolygenObject o) {
		polygenContainer.remove(o);
	}

	public void dropAll(){
		List<IPolygenObject> polygenObjects = polygenContainer.getPolygenObjects();
		if(polygenObjects!=null){
			for(IPolygenObject po : polygenObjects){
				po.drop();
			}
		}
		polygenContainer.clearHoldedObjects();
	}
	
	public void unselectAll(){
		List<IPolygenObject> polygenObjects = polygenContainer.getPolygenObjects();
		if(polygenObjects!=null){
			for(IPolygenObject po : polygenObjects){
				po.unselect();
			}
		}
		polygenContainer.clearSelectedObjects();
	}
	
	@Override
	public void setSelectable() {
		polygenContainer.setSelectable();
	}
	
	@Override
	public void setMergeable() {
		polygenContainer.setMergeable();
	}

	@Override
	public void setLocked() {
		polygenContainer.setLocked();
	}

	@Override
	public IPolygenObject getHolded() {
		if(polygenContainer.getHoldedObjects().size()>0){
			return polygenContainer.getHoldedObjects().get(0);
		}
		return null;
	}
	
	@Override
	public IPolygenObject getSelected() {
		if (polygenContainer.getSelectedObjects().size() > 0) {
			return polygenContainer.getSelectedObjects().get(0);
		}
		return null;
	}
	
	public void updateAll(){
		polygenContainer.update();
	}

	public boolean isMouseDownCatch() {
		return mouseDownCatch;
	}

	public void setMouseDownCatch(boolean mouseDownCatch) {
		this.mouseDownCatch = mouseDownCatch;
	}
	
	
	@Override
	public void setWorkspaceListener(IWorkspaceListener listener) {
		this.workspaceListener = listener;
	}

	@Override
	public void showProperties(IPolygenObject o) {
		editor.showProperties(o);
	}
	
	@Override
	public void showProperties(List<IPolygenObject> oList){
		editor.showProperties(oList);
	}
	
	@Override
	public void setHolded(boolean holded){
		this.mouseClickedX = mouseX;
		this.mouseClickedY = mouseY;
		this.holded = holded;
	}
	
	@Override
	public boolean isHolded() {
		return this.holded;
	}
	
	@Override
	public boolean isSeleceted() {
		return this.selected;
	}

	@Override
	public void setSelected(boolean value) {
		this.selected = value;
		
	}

	@Override
	public void shiftTo(int nx, int ny) {
		int dx = nx - mouseClickedX;
		int dy = ny - mouseClickedY;
		mouseClickedX = nx;
		mouseClickedY = ny;
		scale.shiftOffsetX(dx);
		scale.shiftOffsetY(dy);
		polygenContainer.update();
	}
	
	
	@Override
	public void shiftSelectedObjects(int dx, int dy) {
		double ddx = scale.getDXValue(dx);
		double ddy = scale.getDYValue(dy);
		polygenContainer.shiftSelectedObjects(ddx, ddy);
	}

	@Override
	public void zoom(int delta) {
		scale.zoom(delta);
		polygenContainer.update();
	}

	@Override
	public int getId() {
		return id;
	}

	@Override
	public void setBoundariesVisibility(boolean boundariesVisibility) {
		this.boundariesVisibility = boundariesVisibility;
		if(boundariesVisibility)
			polygenContainer.showBoundaries();
		else
			polygenContainer.hideBoundaries();
	}
	
	@Override
	public boolean getBoundariesVisibility() {
		return this.boundariesVisibility;
	}
	
	@Override
	public void selectObjects(int x1, int y1, int x2, int y2) {
		double dx1 = scale.getModelXValue(x1);
		double dy1 = scale.getModelYValue(y1);
		double dx2 = scale.getModelXValue(x2);
		double dy2 = scale.getModelYValue(y2);
		polygenContainer.selectObjects(dx1, dy1, dx2, dy2);
		showProperties(polygenContainer.getSelectedObjects());
	}
	
	@Override
	public void setMoveable(boolean value) {
		this.moveable = value;
	}
	
	@Override
	public void catchMouseClickedPosition(){
		mouseClickedX = mouseX;
		mouseClickedY = mouseY;
	}



	private class MouseAction implements MouseDownHandler, MouseUpHandler,MouseMoveHandler, MouseWheelHandler{
		
		@Override
		public void onMouseDown(MouseDownEvent event) {
			workspaceListener.onMouseDown(event);
		}

		@Override
		public void onMouseMove(MouseMoveEvent event) {
			workspaceListener.onMouseMove(event);
		}

		@Override
		public void onMouseUp(MouseUpEvent event) {
			workspaceListener.onMouseUp(event);
			setMoveable(false);
		}

		@Override
		public void onMouseWheel(MouseWheelEvent event) {
			workspaceListener.onMouseWheel(event);
		}
		
		
		
	}
	
}